﻿#include "api.h"
#include "stdio.h"
#include "assert.h"
#include "libjpeg/jpeglib.h"

// 公共配置定义
// 5ms进行一次数据收取轮询
#define RECV_QUERY_SLICE	10
#define SIEMA_PORT			5000
#define JPEG_SEG_SIZE		1024
#define SI_BLOCK_SIZE		72
#define TEXT_AREA_X			25
#define TEXT_AREA_Y			47

#ifdef WIN32
#include <winsock2.h>
#include <windows.h>
#include <Ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable: 4996)

void siem_net_init() {
	WORD sockVersion = MAKEWORD(2, 2);
	WSADATA data;
	WSAStartup(sockVersion, &data);
}
#else
void siem_net_init() {
	int iMode = 1;
	struct sockaddr_in localAddr;

	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
	{
		perror("socket function!\n");
		exit(1);
	}

	localAddr.sin_family = AF_INET;
	localAddr.sin_port = htons(SIEMA_PORT);
	localAddr.sin_addr.s_addr = INADDR_ANY;
	if (bind(sockfd, (struct sockaddr *)&localAddr, sizeof(localAddr)) == SOCKET_ERROR) {
		perror("bind function!\n"); exit(1);
	}
	// Non-blocking
	ioctlsocket(sockfd, FIONBIO, (u_long FAR*) &iMode);
}
#endif

typedef struct Udp_conn
{
	SOCKET sockfd;
	struct sockaddr_in sin;
	int len_sin;
	int recv_query_slice;
	int timeout;

	char ipv4[24];
	char device_id[24];
} UDPCONN_t;

int package_str(const char* str, char* buf, int * package_no) {
	if(*package_no == 0)
		*package_no = rand();
	((int*)buf)[0] = *package_no;
	strcpy(buf + 4, str);
	return strlen(str)+ 1 + 4;
}

int siem_broadcast_query(
	int search_time,
	char device_ip[][64],
	char device_name[][64],
	int max_num_device
)
{
	int sockfd;
	struct sockaddr_in dst_addr;
	struct sockaddr_in recv_addr;
	int broadcast = 1;
	int num = 0;
	int iMode = 1;
	int ndevices = 0;
	int i = 0;
	char msg_out[128];
	int len_msg_out = 0;
	int package_no = 0;

	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
	{
		perror("socket function!\n");
		exit(1);
	}
	if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (const char*) &broadcast, sizeof(broadcast)) == -1)
	{
		perror("setsockopt function!\n");
		exit(1);
	}
	// Non-blocking
	ioctlsocket(sockfd, FIONBIO, (u_long FAR*) &iMode);

	dst_addr.sin_family = AF_INET;
	dst_addr.sin_port = htons(SIEMA_PORT);
#ifdef WIN32
	inet_pton(AF_INET, "255.255.255.255", &dst_addr.sin_addr);
#else
	their_addr.sin_addr.s_addr = inet_addr("255.255.255.255");
#endif

	len_msg_out = package_str("query", msg_out, &package_no);
	if ((num = sendto(sockfd, msg_out, len_msg_out, 0,
		(struct sockaddr *)&dst_addr, sizeof(struct sockaddr))) == -1)
	{
		perror("sendto function!\n");
		exit(1);
	}

	printf("Waiting for response.");
#ifdef WIN32
	for (i = 0; i < search_time; i++) {
		// Wait for search_time
		Sleep(1000);
		printf(".");
	}
#else
	for (i = 0; i < search_time; i++) {
		// Wait for search_time
		Sleep(1000);
		printf(".");
	}
#endif

	while (1) {
		char recvBuf[1024];
		int valid_no = 0;
		int len_addr = sizeof(struct sockaddr_in);
		int res = recvfrom(sockfd, recvBuf, 1024, 0, (struct sockaddr*) &recv_addr, &len_addr);
		char* token = 0;
		if (res == -1)
			break;

		valid_no = *((int*)recvBuf);
		if (valid_no != package_no)
			continue;

		token = strtok(recvBuf+4, ":");
		if (token) {
			strcpy(device_name[ndevices], token);
		}
		if (token != NULL)
		{
			/* Get next token: */
			token = strtok(NULL, ":");
			strcpy(device_ip[ndevices], token);
			ndevices++;
		}
	}

	printf("\n");
	return ndevices;
}

HCTX siem_context(
	int local_port
)
{
	int sockfd;
	int iMode = 1;
	struct sockaddr_in localAddr;

	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
		perror("socket function!\n");
		return 0;
	}

	localAddr.sin_family = AF_INET;
	localAddr.sin_port = htons(local_port);
	localAddr.sin_addr.s_addr = INADDR_ANY;

	if (local_port == 0) {
		local_port = 5000;
		while (1) {
			if (bind(sockfd, (struct sockaddr *)&localAddr, sizeof(localAddr)) == SOCKET_ERROR) {
				local_port++;
			}
			else {
				break;
			}
			if (local_port >= 30000) {
				perror("bind function!\n");
				return 0;
			}
		}
	}
	else {
		if (bind(sockfd, (struct sockaddr *)&localAddr, sizeof(localAddr)) == SOCKET_ERROR) {
			perror("bind function!\n");
			return 0;
		}
	}

	// Non-blocking
	ioctlsocket(sockfd, FIONBIO, (u_long FAR*) &iMode);

	return (HCTX)sockfd;
}

HSIEM siem_connect(
	HCTX ctx,
	const char* device_ip,
	int timeout
)
{
	UDPCONN_t* con = (UDPCONN_t*)calloc(1, sizeof(UDPCONN_t));
	int ticks = 0;
	int res = 0;
	char msg_out[128];
	int len_msg_out = 0;
	int package_no = 0;

	strcpy(con->ipv4, device_ip);

	con->sockfd = (int) ctx;
	con->recv_query_slice = RECV_QUERY_SLICE;
	con->timeout = timeout * 1000;

	if ((con->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
	{
		perror("socket function!\n");
		exit(1);
	}

	con->sin.sin_family = AF_INET;
	con->sin.sin_port = htons(SIEMA_PORT);
	printf("connect to: %s\n", con->ipv4);
#ifdef WIN32
	inet_pton(AF_INET, con->ipv4, &con->sin.sin_addr);
#else
	their_addr.sin_addr.s_addr = inet_addr(con->ipv4);
#endif
	con->len_sin = sizeof(con->sin);

	len_msg_out = package_str("device_id", msg_out, &package_no);
	if ((res = sendto(con->sockfd, msg_out, len_msg_out, 0,
		(struct sockaddr *)&con->sin, sizeof(struct sockaddr))) == -1)
	{
		perror("sendto function!\n");
		exit(1);
	}

	while (ticks < con->timeout) {
		char recvBuf[64];
		int valid_no;
		int res = recv(con->sockfd, recvBuf, 64, 0);
		if (res <= 0) {
			Sleep(con->recv_query_slice);
			ticks += con->recv_query_slice;
			continue;
		}
		valid_no = *((int*)recvBuf);
		if (valid_no != package_no)
			continue;
		strcpy(con->device_id, recvBuf+4);
		break;
	}
	printf("%s connected.\n", con->device_id);
	return con;
}

void siem_disconnect(HSIEM siem)
{
	UDPCONN_t* con = (UDPCONN_t*)siem;
	if(con)
		free(con);
}

void siem_context_free(
	HCTX ctx
)
{
	closesocket((int)ctx);
}

int siem_get_jpeg(
	HSIEM siem,
	unsigned char* data,
	int * len_data
)
{
	UDPCONN_t* con = (UDPCONN_t*)siem;
#ifdef WIN32
	DWORD t0, t1;
#endif
	int iMode = 1;
	int ticks = 0;
	int res = 0;
	char msg_out[128];
	int len_msg_out = 0;
	int package_no = 0;
	int total_size = 0;
	int recv_size = 0;
	int has_resend = 0;
	// package_lost用来保存每个package是否已经收到，1为收到，0未收到;
	char package_lost[128] = {0};

#ifdef WIN32
	t0 = timeGetTime();
#endif
	// 发送获取图像的命令
	len_msg_out = package_str("img", msg_out, &package_no);
	if ((res = sendto(con->sockfd, msg_out, len_msg_out, 0,
		(struct sockaddr *)&con->sin, sizeof(struct sockaddr))) == -1)
	{
		perror("sendto function!\n");
		exit(1);
	}
	ioctlsocket(con->sockfd, FIONBIO, (u_long FAR*) &iMode);

	while (ticks < con->timeout) {
		char recvBuf[1280];
		int valid_no;
		int i, max_packages;
		int res = recv(con->sockfd, recvBuf, 1280, 0);
		if (res <= 0) {
			Sleep(con->recv_query_slice);
			ticks += con->recv_query_slice;
			// 如果已经拿到了total_size，那么在某个程度上可以考虑重传一次
			// 可能的UDP丢包，直到所有的包都收到为止;
			// 这块可以不实现;
			if (total_size != 0 && !has_resend) {
				// 发送丢包重传
				int nreceived = 0;
				max_packages = total_size / JPEG_SEG_SIZE;
				if (total_size % JPEG_SEG_SIZE != 0)
					max_packages++;
				for (i = 0; i < max_packages; i++) {
					if (package_lost[i] == 1)
						nreceived++;
				}
				if (nreceived > 3 * total_size / 4) {
					printf("resend query when %d time passed.\n", ticks);
					has_resend = 1;
					for (i = 0; i < max_packages; i++) {
						char msg[24];
						if (package_lost[i] == 1)
							continue;
						sprintf(msg, "img-lost%d", i);
						len_msg_out = package_str(msg, msg_out, &package_no);
						if ((res = sendto(con->sockfd, msg_out, len_msg_out, 0,
							(struct sockaddr *)&con->sin, sizeof(struct sockaddr))) == -1)
						{
							perror("sendto function!\n");
							exit(1);
						}
					}
				}
			}
			// 如果200ms以后还没有收到数据大小帧，我们需要重新采集图像
			// else if (total_size == 0 && ticks >= 200) {
			//	return SIEM_ERR_TIMEOUT;
			// }
			continue;
		}

		// valid_no必需保证相同才为当前命令的回包，否则丢弃
		valid_no = *((int*)recvBuf);
		if (valid_no != package_no)
			continue;

		// 当前三个字符为bin时，后面跟的就是bin的大小
		if (strncmp(recvBuf + 4, "bin", 3) == 0) {
			sscanf(recvBuf + 7, "%d", &total_size);
		} 
		else {
			int data_offset = ((int*)recvBuf)[1];
			int copy_size = min(res - 8, *len_data - data_offset);
			if (copy_size > 0) {
				package_lost[data_offset / JPEG_SEG_SIZE] = 1;
				memcpy(data + data_offset, recvBuf + 8, copy_size);
				recv_size += res - 8;
			}
		}

		if (total_size != 0 && recv_size >= total_size) {
			int canbreak = 1;
			max_packages = total_size / JPEG_SEG_SIZE;
			if (total_size % JPEG_SEG_SIZE != 0)
				max_packages++;
			for (i = 0; i < max_packages; i++) {
				if (package_lost[i] == 0) {
					canbreak = 0;
					break;
				}
			}
			if (canbreak)
				break;
		}
	}

#ifdef WIN32
	t1 = timeGetTime();
	printf("1 frame cost: %d\n", t1 - t0);
#endif

	*len_data = total_size;
	if (ticks < con->timeout)
		return 0;
	else
		return SIEM_ERR_TIMEOUT;
}

extern char textcode_0[];
extern char textcode_1[];
extern char textcode_2[];
extern char textcode_3[];
extern char textcode_4[];
extern char textcode_5[];
extern char textcode_6[];
extern char textcode_7[];
extern char textcode_8[];
extern char textcode_9[];

// 颜色映射表
float rr[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.00588235294117645f,0.02156862745098032f,0.03725490196078418f,0.05294117647058827f,0.06862745098039214f,0.084313725490196f,0.1000000000000001f,0.115686274509804f,0.1313725490196078f,0.1470588235294117f,0.1627450980392156f,0.1784313725490196f,0.1941176470588235f,0.2098039215686274f,0.2254901960784315f,0.2411764705882353f,0.2568627450980392f,0.2725490196078431f,0.2882352941176469f,0.303921568627451f,0.3196078431372549f,0.3352941176470587f,0.3509803921568628f,0.3666666666666667f,0.3823529411764706f,0.3980392156862744f,0.4137254901960783f,0.4294117647058824f,0.4450980392156862f,0.4607843137254901f,0.4764705882352942f,0.4921568627450981f,0.5078431372549019f,0.5235294117647058f,0.5392156862745097f,0.5549019607843135f,0.5705882352941174f,0.5862745098039217f,0.6019607843137256f,0.6176470588235294f,0.6333333333333333f,0.6490196078431372f,0.664705882352941f,0.6803921568627449f,0.6960784313725492f,0.7117647058823531f,0.7274509803921569f,0.7431372549019608f,0.7588235294117647f,0.7745098039215685f,0.7901960784313724f,0.8058823529411763f,0.8215686274509801f,0.8372549019607844f,0.8529411764705883f,0.8686274509803922f,0.884313725490196f,0.8999999999999999f,0.9156862745098038f,0.9313725490196076f,0.947058823529412f,0.9627450980392158f,0.9784313725490197f,0.9941176470588236f,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.9862745098039216f,0.9705882352941178f,0.9549019607843139f,0.93921568627451f,0.9235294117647062f,0.9078431372549018f,0.892156862745098f,0.8764705882352941f,0.8607843137254902f,0.8450980392156864f,0.8294117647058825f,0.8137254901960786f,0.7980392156862743f,0.7823529411764705f,0.7666666666666666f,0.7509803921568627f,0.7352941176470589f,0.719607843137255f,0.7039215686274511f,0.6882352941176473f,0.6725490196078434f,0.6568627450980391f,0.6411764705882352f,0.6254901960784314f,0.6098039215686275f,0.5941176470588236f,0.5784313725490198f,0.5627450980392159f,0.5470588235294116f,0.5313725490196077f,0.5156862745098039f,0.5f };
float gg[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.001960784313725483f,0.01764705882352935f,0.03333333333333333f,0.0490196078431373f,0.06470588235294117f,0.08039215686274503f,0.09607843137254901f,0.111764705882353f,0.1274509803921569f,0.1431372549019607f,0.1588235294117647f,0.1745098039215687f,0.1901960784313725f,0.2058823529411764f,0.2215686274509804f,0.2372549019607844f,0.2529411764705882f,0.2686274509803921f,0.2843137254901961f,0.3f,0.3156862745098039f,0.3313725490196078f,0.3470588235294118f,0.3627450980392157f,0.3784313725490196f,0.3941176470588235f,0.4098039215686274f,0.4254901960784314f,0.4411764705882353f,0.4568627450980391f,0.4725490196078431f,0.4882352941176471f,0.503921568627451f,0.5196078431372548f,0.5352941176470587f,0.5509803921568628f,0.5666666666666667f,0.5823529411764705f,0.5980392156862746f,0.6137254901960785f,0.6294117647058823f,0.6450980392156862f,0.6607843137254901f,0.6764705882352942f,0.692156862745098f,0.7078431372549019f,0.723529411764706f,0.7392156862745098f,0.7549019607843137f,0.7705882352941176f,0.7862745098039214f,0.8019607843137255f,0.8176470588235294f,0.8333333333333333f,0.8490196078431373f,0.8647058823529412f,0.8803921568627451f,0.8960784313725489f,0.9117647058823528f,0.9274509803921569f,0.9431372549019608f,0.9588235294117646f,0.9745098039215687f,0.9901960784313726f,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.9901960784313726f,0.9745098039215687f,0.9588235294117649f,0.943137254901961f,0.9274509803921571f,0.9117647058823528f,0.8960784313725489f,0.8803921568627451f,0.8647058823529412f,0.8490196078431373f,0.8333333333333335f,0.8176470588235296f,0.8019607843137253f,0.7862745098039214f,0.7705882352941176f,0.7549019607843137f,0.7392156862745098f,0.723529411764706f,0.7078431372549021f,0.6921568627450982f,0.6764705882352944f,0.6607843137254901f,0.6450980392156862f,0.6294117647058823f,0.6137254901960785f,0.5980392156862746f,0.5823529411764707f,0.5666666666666669f,0.5509803921568626f,0.5352941176470587f,0.5196078431372548f,0.503921568627451f,0.4882352941176471f,0.4725490196078432f,0.4568627450980394f,0.4411764705882355f,0.4254901960784316f,0.4098039215686273f,0.3941176470588235f,0.3784313725490196f,0.3627450980392157f,0.3470588235294119f,0.331372549019608f,0.3156862745098041f,0.2999999999999998f,0.284313725490196f,0.2686274509803921f,0.2529411764705882f,0.2372549019607844f,0.2215686274509805f,0.2058823529411766f,0.1901960784313728f,0.1745098039215689f,0.1588235294117646f,0.1431372549019607f,0.1274509803921569f,0.111764705882353f,0.09607843137254912f,0.08039215686274526f,0.06470588235294139f,0.04901960784313708f,0.03333333333333321f,0.01764705882352935f,0.001960784313725483f,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
float bb[] = { 0.5f,0.5156862745098039f,0.5313725490196078f,0.5470588235294118f,0.5627450980392157f,0.5784313725490196f,0.5941176470588235f,0.6098039215686275f,0.6254901960784314f,0.6411764705882352f,0.6568627450980392f,0.6725490196078432f,0.6882352941176471f,0.7039215686274509f,0.7196078431372549f,0.7352941176470589f,0.7509803921568627f,0.7666666666666666f,0.7823529411764706f,0.7980392156862746f,0.8137254901960784f,0.8294117647058823f,0.8450980392156863f,0.8607843137254902f,0.8764705882352941f,0.892156862745098f,0.907843137254902f,0.9235294117647059f,0.9392156862745098f,0.9549019607843137f,0.9705882352941176f,0.9862745098039216f,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.9941176470588236f,0.9784313725490197f,0.9627450980392158f,0.9470588235294117f,0.9313725490196079f,0.915686274509804f,0.8999999999999999f,0.884313725490196f,0.8686274509803922f,0.8529411764705883f,0.8372549019607844f,0.8215686274509804f,0.8058823529411765f,0.7901960784313726f,0.7745098039215685f,0.7588235294117647f,0.7431372549019608f,0.7274509803921569f,0.7117647058823531f,0.696078431372549f,0.6803921568627451f,0.6647058823529413f,0.6490196078431372f,0.6333333333333333f,0.6176470588235294f,0.6019607843137256f,0.5862745098039217f,0.5705882352941176f,0.5549019607843138f,0.5392156862745099f,0.5235294117647058f,0.5078431372549019f,0.4921568627450981f,0.4764705882352942f,0.4607843137254903f,0.4450980392156865f,0.4294117647058826f,0.4137254901960783f,0.3980392156862744f,0.3823529411764706f,0.3666666666666667f,0.3509803921568628f,0.335294117647059f,0.3196078431372551f,0.3039215686274508f,0.2882352941176469f,0.2725490196078431f,0.2568627450980392f,0.2411764705882353f,0.2254901960784315f,0.2098039215686276f,0.1941176470588237f,0.1784313725490199f,0.1627450980392156f,0.1470588235294117f,0.1313725490196078f,0.115686274509804f,0.1000000000000001f,0.08431372549019622f,0.06862745098039236f,0.05294117647058805f,0.03725490196078418f,0.02156862745098032f,0.00588235294117645f,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };

void get_text_size(const char* txt, int* w, int * h) {
	*w = strlen(txt) * TEXT_AREA_X;
	*h = TEXT_AREA_Y;
}

// 生成伪彩色图
int siem_pt_image_16x4(
	float t[64],
	float mint,
	float maxt,
	// bgr 应该是 [SI_BLOCK_SIZE * 16, SI_BLOCK_SIZE * 4] 大小的图像
	unsigned char* bgr
)
{
	int i, j;
	int stride = SI_BLOCK_SIZE * 16 * 3;
	char* textcodes[] = {
		textcode_0,
		textcode_1,
		textcode_2,
		textcode_3,
		textcode_4,
		textcode_5,
		textcode_6,
		textcode_7,
		textcode_8,
		textcode_9
	};
	for (j = 0; j < 4; j++) {
		for (i = 0; i < 16; i++) {
			float tm = t[j * 16 + i];
			char b, g, r;
			int left = i*SI_BLOCK_SIZE; 
			int right = (i+1)*SI_BLOCK_SIZE; 
			int top = j*SI_BLOCK_SIZE;
			int bottom = (j+1)*SI_BLOCK_SIZE;
			int x, y, k;
			int cx, cy;
			int ts_x, ts_y;
			char* textcode_ptr;
			char tstr[6];
			tm = max(tm, mint);
			tm = min(tm, maxt);
			b = (char)(bb[(int)(256 - 256 * (tm - mint) / (maxt - mint))] * 255);
			g = (char)(gg[(int)(256 - 256 * (tm - mint) / (maxt - mint))] * 255);
			r = (char)(rr[(int)(256 - 256 * (tm - mint) / (maxt - mint))] * 255);
			for (y = top; y < bottom; y++) {
				for (x = left; x < right; x++) {
					bgr[y*stride + 3 * x] = b;
					bgr[y*stride + 3 * x + 1] = g;
					bgr[y*stride + 3 * x + 2] = r;
				}
			}
			sprintf(tstr, "%d", (int)(tm+0.5f));
			get_text_size(tstr, &ts_x, &ts_y);
			cx = ((right - left) - ts_x) / 2;
			cy = ((bottom - top) - ts_y) / 2;
			for (k = 0; k < (int)strlen(tstr); k++) {
				textcode_ptr = textcodes[tstr[k] - '0'];
				for (y = 0; y < TEXT_AREA_Y; y++) {
					for (x = 0; x < TEXT_AREA_X; x++) {
						if (textcode_ptr[y*TEXT_AREA_X + x] == 1) {
							int idx = (top + cy + y)*stride + 3 * (left + cx + x + k*TEXT_AREA_X);
							if (bgr[idx] > bgr[idx + 2]) {
								//bgr[idx] = 255;
								bgr[idx + 1] = 128;
								bgr[idx + 2] = 255;
								bgr[idx] = 255;
								bgr[idx + 1] = 0;
								bgr[idx + 2] = 0;
							}
							else {
								bgr[idx] = 255;
								bgr[idx + 1] = 128;
								//bgr[idx + 2] = 0;
								bgr[idx] = 255;
								bgr[idx + 1] = 0;
								bgr[idx + 2] = 0;
							}
						}
					}
				}
			}
		}
	}
	return 0;
}

extern void disp_img(unsigned char* data, int w, int h, int stride);
int siem_get_fusion(
	HSIEM siem,
	unsigned char* bgr,
	int *w, 
	int *h,
	int *stride,
	float low_tempa,
	float high_tempa,
	int do_compression
)
{
	struct jpeg_decompress_struct cinfo;
	struct jpeg_error_mgr jerr;

	int res = 0;
	int i, j;
	unsigned char* jpeg_data = (unsigned char*)malloc(256 * 1024);
	unsigned char* t_bgr_data = (unsigned char*)malloc(SI_BLOCK_SIZE * 16 * SI_BLOCK_SIZE * 4 * 3);
	float tdata[64] = {0};
	float scalex, scaley;
	float offset_x, offset_y;
	int len = sizeof(float) * 64;
	res = siem_get_temperature(siem, tdata, &len);
	if (res != 0)
		goto exit;

	len = 256 * 1024; // 256K
	res = siem_get_jpeg(siem, jpeg_data, &len);
	if (res != 0)
		goto exit;

	// 解码
	// 图像叠加
	cinfo.err = jpeg_std_error(&jerr);
	jpeg_create_decompress(&cinfo);

	// 解压
	jpeg_mem_src(&cinfo, jpeg_data, len);
	jpeg_read_header(&cinfo, TRUE);
	if ((int)(cinfo.image_width*cinfo.image_height*3) < *h * *stride) {
		res = SIEM_ERR_NOMEMORY;
		goto exit;
	}
	*w = cinfo.image_width;
	*h = cinfo.image_height;
	*stride = cinfo.image_width * 3;
	jpeg_start_decompress(&cinfo);
	JSAMPROW row_pointer[1];
	while (cinfo.output_scanline < cinfo.output_height)
	{
		// row_pointer[0] = &bgr_data[(cinfo.output_height - cinfo.output_scanline - 1)*cinfo.image_width*cinfo.num_components];
		row_pointer[0] = &bgr[cinfo.output_scanline*cinfo.image_width*cinfo.num_components];
		jpeg_read_scanlines(&cinfo, row_pointer, 1);
	}
	jpeg_finish_decompress(&cinfo);
	jpeg_destroy_decompress(&cinfo);

	// 生成伪彩温度图像
	siem_pt_image_16x4(tdata, low_tempa, high_tempa, t_bgr_data);
	// disp_img(t_bgr_data, SI_BLOCK_SIZE * 16, SI_BLOCK_SIZE * 4, SI_BLOCK_SIZE * 16 * 3);

	// 拿到融合参数
	scalex = 1.f / ((float)cinfo.image_width / 800 * (800 / 1152.f));
	scaley = 1.f / ((float)cinfo.image_height / 600 * (800 / 1152.f));
	offset_x = 0 * (float)cinfo.image_width / 800;
	offset_y = 300 * (float)cinfo.image_height / 600;

	// 混合可见光与彩色图像
	for (j = 0; j < (int)cinfo.image_height; j++) {
		for (i = 0; i < (int)cinfo.image_width; i++) {
			int x, y;
			unsigned char* ptr1, *ptr2;
			x = (int)(scalex * i - offset_x);
			y = (int)(scaley * j - offset_y);
			if (x < 0 || x >= SI_BLOCK_SIZE * 16 || y < 0 || y >= SI_BLOCK_SIZE * 4)
				continue;
			ptr1 = bgr + j**stride + 3 * i;
			ptr2 = t_bgr_data + y*SI_BLOCK_SIZE * 16 * 3 + 3 * x;
			ptr1[0] = (ptr2[0] + ptr1[0]) / 2;
			ptr1[1] = (ptr2[1] + ptr1[1]) / 2;
			ptr1[2] = (ptr2[2] + ptr1[2]) / 2;
		}
	}

exit:
	free(jpeg_data);
	free(t_bgr_data);
	return res;
}

int siem_get_temperature(
	HSIEM siem,
	float * data,
	int * len_data
)
{
	UDPCONN_t* con = (UDPCONN_t*)siem;
#ifdef WIN32
	DWORD t0, t1;
#endif
	int iMode = 1;
	int ticks = 0;
	int res = 0;
	char msg_out[128];
	int len_msg_out = 0;
	int package_no = 0;
	int total_size = 0;
	int recv_size = 0;
	int i, j;

#ifdef WIN32
	t0 = timeGetTime();
#endif

	len_msg_out = package_str("them", msg_out, &package_no);
	if ((res = sendto(con->sockfd, msg_out, len_msg_out, 0,
		(struct sockaddr *)&con->sin, sizeof(struct sockaddr))) == -1)
	{
		perror("sendto function!\n");
		exit(1);
	}
	ioctlsocket(con->sockfd, FIONBIO, (u_long FAR*) &iMode);

	while (ticks < con->timeout) {
		char recvBuf[1280];
		int valid_no;
		int res = recv(con->sockfd, recvBuf, 1280, 0);
		if (res <= 0) {
			Sleep(con->recv_query_slice);
			ticks += con->recv_query_slice;
			continue;
		}
		valid_no = *((int*)recvBuf);
		if (valid_no != package_no)
			continue;

		*len_data = (res - 4) / sizeof(float);
		if (*len_data != 64) {
			return SIEM_ERR_DATA;
		}
		memcpy(data, recvBuf + 4, *len_data * sizeof(float));
		break;
	}

#ifdef WIN32
	t1 = timeGetTime();
	printf("1 frame cost: %d\n", t1 - t0);
#endif

	// 左右镜像，配合可见光
	for (j = 0; j < 4; j++) {
		for (i = 0; i < 8; i++) {
			float t = data[j * 16 + i];
			data[j * 16 + i] = data[j * 16 + 15 - i];
			data[j * 16 + 15 - i] = t;
		}
	}

	if (ticks < con->timeout)
		return 0;
	else
		return SIEM_ERR_TIMEOUT;
}

int siem_set_param(
	HSIEM siem,
	char* param_name,
	char* param_value
)
{
	UDPCONN_t* con = (UDPCONN_t*)siem;

	int iMode = 1;
	int ticks = 0;
	int res = 0;
	char msg_out[128];
	char cmd[124];
	int len_msg_out = 0;
	int package_no = 0;

	sprintf(cmd, "%s%s", param_name, param_value);
	len_msg_out = package_str(cmd, msg_out, &package_no);
	if ((res = sendto(con->sockfd, msg_out, len_msg_out, 0,
		(struct sockaddr *)&con->sin, sizeof(struct sockaddr))) == -1)
	{
		perror("sendto function!\n");
		exit(1);
	}
	ioctlsocket(con->sockfd, FIONBIO, (u_long FAR*) &iMode);

	while (ticks < con->timeout) {
		char recvBuf[1280];
		int valid_no;
		int res = recv(con->sockfd, recvBuf, 1280, 0);
		if (res <= 0) {
			Sleep(con->recv_query_slice);
			ticks += con->recv_query_slice;
			continue;
		}
		valid_no = *((int*)recvBuf);
		if (valid_no != package_no)
			continue;

		strcpy(param_value, recvBuf+4);
		break;
	}

	if (ticks < con->timeout)
		return 0;
	else
		return SIEM_ERR_TIMEOUT;
}

int siem_get_param(
	HSIEM siem,
	char* param_name,
	char* param_value
)
{
	UDPCONN_t* con = (UDPCONN_t*)siem;

	int iMode = 1;
	int ticks = 0;
	int res = 0;
	char msg_out[128];
	char cmd[124];
	int len_msg_out = 0;
	int package_no = 0;

	sprintf(cmd, "%s", param_name);
	len_msg_out = package_str(cmd, msg_out, &package_no);
	if ((res = sendto(con->sockfd, msg_out, len_msg_out, 0,
		(struct sockaddr *)&con->sin, sizeof(struct sockaddr))) == -1)
	{
		perror("sendto function!\n");
		exit(1);
	}
	ioctlsocket(con->sockfd, FIONBIO, (u_long FAR*) &iMode);

	while (ticks < con->timeout) {
		char recvBuf[1280];
		int valid_no;
		int res = recv(con->sockfd, recvBuf, 1280, 0);
		if (res <= 0) {
			Sleep(con->recv_query_slice);
			ticks += con->recv_query_slice;
			continue;
		}
		valid_no = *((int*)recvBuf);
		if (valid_no != package_no)
			continue;

		strcpy(param_value, recvBuf + 4);
		break;
	}

	if (ticks < con->timeout)
		return 0;
	else
		return SIEM_ERR_TIMEOUT;
}

int siem_restart(
	HSIEM siem
)
{
	UDPCONN_t* con = (UDPCONN_t*)siem;

	int iMode = 1;
	int ticks = 0;
	int res = 0;
	char msg_out[128];
	char cmd[124];
	int len_msg_out = 0;
	int package_no = 0;

	sprintf(cmd, "restart");
	len_msg_out = package_str(cmd, msg_out, &package_no);
	if ((res = sendto(con->sockfd, msg_out, len_msg_out, 0,
		(struct sockaddr *)&con->sin, sizeof(struct sockaddr))) == -1)
	{
		perror("sendto function!\n");
		exit(1);
	}
	ioctlsocket(con->sockfd, FIONBIO, (u_long FAR*) &iMode);

	while (ticks < con->timeout) {
		char recvBuf[1280];
		int valid_no;
		int res = recv(con->sockfd, recvBuf, 1280, 0);
		if (res <= 0) {
			Sleep(con->recv_query_slice);
			ticks += con->recv_query_slice;
			continue;
		}
		valid_no = *((int*)recvBuf);
		if (valid_no != package_no)
			continue;
		if (strcmp(recvBuf + 4, "ack") != 0) {
			return SIEM_ERR_DATA;
		}
		break;
	}

	if (ticks < con->timeout)
		return 0;
	else
		return SIEM_ERR_TIMEOUT;
}

int siem_bin_update(
	HSIEM siem,
	const char* bin_file
)
{
	UDPCONN_t* con = (UDPCONN_t*)siem;

	int iMode = 1;
	int ticks = 0;
	int res = 0;
	char codebuffer[512+16];
	int len_msg_out = 0;
	int bytesended = 0;
	FILE* pf;

	pf = fopen(bin_file, "rb");
	if (!pf)
		return SIEM_ERR_NOFILE;

	while ( 1 ) {
		int package_no = rand();
		int nread = 0;

		memset(codebuffer, 0, 512 + 16);
		*(int*)codebuffer = package_no;
		strcpy(codebuffer + 4, "update00");
		*(int*)(codebuffer + 12) = bytesended;
		nread = fread(codebuffer + 16, 1, 512, pf);
		if (nread <= 0)
			break;
		bytesended += nread;

		if ((res = sendto(con->sockfd, codebuffer, 512 + 16, 0,
			(struct sockaddr *)&con->sin, sizeof(struct sockaddr))) == -1)
		{
			perror("bad sendto function!\n");
			exit(1);
		}
		ioctlsocket(con->sockfd, FIONBIO, (u_long FAR*) &iMode);

		while (ticks < con->timeout) {
			char recvBuf[24];
			int valid_no;
			int res = recv(con->sockfd, recvBuf, 24, 0);
			if (res <= 0) {
				Sleep(con->recv_query_slice);
				ticks += con->recv_query_slice;
				continue;
			}
			valid_no = *((int*)recvBuf);
			if (valid_no != package_no)
				continue;
			if (strcmp(recvBuf + 4, "ack") != 0) {
				printf(recvBuf + 4);
				fclose(pf);
				return SIEM_ERR_DATA;
			}
			printf(".");
			break;
		}

		if (nread < 512)
			break;
	}

	printf("\n");
	fclose(pf);
	if (ticks < con->timeout)
		return 0;
	else
		return SIEM_ERR_TIMEOUT;
}